﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ace_pso.Utility;

namespace ace_pso
{
    public partial class Form1 : Form
    {
        #region 参数和变量

        private double c1 = 1;
        private double c2 = 1;

        private double w = 1;//惯性 
        private Random random = new Random();
        private int familySize = 100;
        private int iterationTimes = 5;

        private BackgroundWorker bgWorker;
        #endregion

        public Form1()
        {
            InitializeComponent();
        }



        private void btnStart_Click(object sender, EventArgs e)
        {
            bgWorker = new BackgroundWorker();
            bgWorker.DoWork += DoWork;
            bgWorker.ProgressChanged += ShowProgress;
            bgWorker.RunWorkerCompleted += WorkCompleted;
            bgWorker.WorkerReportsProgress = true;
            bgWorker.WorkerSupportsCancellation = true;

            familySize = Convert.ToInt32(tbxParticleSize.Text);
            iterationTimes = Convert.ToInt32(tbxIterationTimes.Text);

            btnStart.Enabled = false;
            tbxIterationTimes.Enabled = false;
            tbxParticleSize.Enabled = false;

            bgWorker.RunWorkerAsync();
        }

        private void DoWork(object sender, DoWorkEventArgs e)
        {
            #region 测试整个搜索空间的适应值分布情况
            /*
            for (int i = 0; i < 1000; i++)
            {
                Particle particle = GetRandomInitialParticle();

                ComputeFitness(particle);
                double fit = particle.Fitness;
                StringBuilder position = new StringBuilder();
                for (int j = 0; j < 3; j++)
                {
                    for (int k = 0; k < 10; k++)
                    {
                        position.Append(particle.Position[j, k]);
                    }
                    position.Append(";");
                }
                Trace.WriteLine(string.Format("{0}    {1}", position, fit));
            }


            return;
            */
            #endregion


            //粒子群算法

            //生产初始粒子群
            List<Particle> particles0 = GetInitialParticles();
            List<KeyValuePair<int, double>> gBestProfitHis = new List<KeyValuePair<int, double>>();//全局最优点 收益的优化历史
            List<KeyValuePair<int, double>> gBestRiskHis = new List<KeyValuePair<int, double>>();//全局最优点 风险的优化历史
            double gBestProfit = double.NegativeInfinity;// 
            double gBestRisk = double.PositiveInfinity;// 

            //记录gbest
            Particle bestParticel = new Particle();
            bestParticel.Position = new double[3, 10];

            double bestFitness = double.NegativeInfinity;//设置为负无穷




            //开始迭代
            bool stop = false;
            for (int i = 0; i < iterationTimes; i++)
            {
                bgWorker.ReportProgress(100 * (i + 1) / iterationTimes, i + 1);
                //if (stop)
                //    break;
                Trace.WriteLine(string.Format("第次{0}迭代,最优适应值：{1}", i + 1, bestFitness));
                //Trace.WriteLine(bestFitness);



                //循环群中每个粒子，计算适应度，有问题，两个目标的怎么计算适应值？
                //gbest和pbest是最好的z，也就是position

                //更新粒子状态(速度和位置)
                //注意：这里需要保证第一个计划期的z是1,所以第一个计划期的就不变了
                foreach (Particle particle in particles0)
                {
                    //int z = particle.Position.Length;
                    for (int j = 1; j < 3; j++)
                    {
                        for (int k = 0; k < 10; k++)
                        {
                            particle.Velocity[j, k] =
                                w * particle.Velocity[j, k] +
                                c1 * random.NextDouble() * (particle.PBestPosition[j, k] - particle.Position[j, k])
                                + c2 * random.NextDouble() * (bestParticel.Position[j, k] - particle.Position[j, k]);

                            if (random.NextDouble() < SigMoid(particle.Velocity[j, k]))
                            {
                                particle.Position[j, k] = 1;
                            }
                            else
                            {
                                particle.Position[j, k] = 0;

                            }
                        }
                    }
                    //这里需要保证是可行的 使用能力捆绑算法 也就是把0-1同化了
                    CapacityBundle(particle);
                }

                //寻找gbest
                foreach (Particle particle in particles0)
                {
                    ComputeFitness(particle);
                }

                //todo:排序 收益方向
                particles0 = particles0.OrderBy(p => p.Profit).ToList();

                for (int j = 0; j < particles0.Count; j++)
                {
                    List<Particle> p2 = new List<Particle>();
                    p2.Add(particles0[j]);
                    if (j > 0)
                        p2.Add(particles0[j - 1]);
                    if (j > 1)
                        p2.Add(particles0[j - 2]);

                    if (j < particles0.Count - 1)
                        p2.Add(particles0[j + 1]);
                    if (j < particles0.Count - 2)
                        p2.Add(particles0[j + 2]);

                    //从选择出来的几个粒子中 寻找最小风险的点 去更新
                    Particle pBest = p2.OrderBy(p => p.Risk).First();

                    if (pBest.Profit > particles0[j].PBestProfit || pBest.Risk < particles0[j].PBestRisk)
                    {
                        particles0[j].PBestProfit = pBest.Profit;
                        particles0[j].PBestRisk = pBest.Risk;
                        particles0[j].PBestPosition = pBest.Position;
                    }

                    if (pBest.Profit > gBestProfit && pBest.Risk < gBestRisk)
                    {
                        gBestProfit = pBest.Profit;
                        gBestRisk = pBest.Risk;
                        bestParticel.Position = pBest.Position;
                    }

                }


                //foreach (Particle particle in particles0)
                //{
                //    //从排好序的List里面选出来 临近的几个粒子



                //    //更新pbest
                //    if (particle.Fitness > particle.PBestFitness)//todo：需要修改最优点的选择方法，不是这么简单的比较适应值
                //    {
                //        particle.PBestFitness = particle.Fitness;
                //        particle.PBestPosition = particle.Position;

                //        particle.PBestProfit = particle.Profit;
                //        particle.PBestRisk = particle.Risk;
                //    }

                //    particle.PBestProfitHis.Add(new KeyValuePair<int, double>(i, particle.PBestProfit));
                //    particle.PBestRiskHis.Add(new KeyValuePair<int, double>(i, particle.PBestRisk));

                //    //更新gbest
                //    if (particle.Fitness > bestFitness)
                //    {
                //        bestFitness = particle.Fitness;
                //        bestParticel = particle;
                //        gBestProfit = particle.Profit;
                //        gBestRisk = particle.Risk;
                //    }

                //    Trace.WriteLine(string.Format("{0}  {1}", particle.Profit, particle.Risk));
                //}

                //gBestProfitHis.Add(new KeyValuePair<int, double>(i + 1, gBestProfit));
                //gBestRiskHis.Add(new KeyValuePair<int, double>(i + 1, gBestRisk));

                DataGateWay.InsertGBest(i + 1, gBestProfit, gBestRisk);

            }

            foreach (Particle particle in particles0)
            {
                DataGateWay.InsertPBest(particle.PBestProfit, particle.PBestRisk);
            }


            //计算完成，存储计算结果
            //StringBuilder sbProfit = new StringBuilder();
            //sbProfit.AppendLine("-------------------gBest Profit His-------------------");
            //foreach (KeyValuePair<int, double> keyValuePair in gBestProfitHis)
            //{
            //    sbProfit.AppendLine(keyValuePair.Value.ToString());
            //}

            //StringBuilder sbRisk = new StringBuilder();
            //sbRisk.AppendLine("-------------------gBest Risk His-------------------");
            //foreach (KeyValuePair<int, double> keyValuePair in gBestRiskHis)
            //{
            //    sbRisk.AppendLine(keyValuePair.Value.ToString());
            //}

            //StringBuilder sbPBest = new StringBuilder();
            //sbPBest.AppendLine("-------------------pBest points at the end-------------------");
            //foreach (Particle particle in particles0)
            //{
            //    sbPBest.AppendLine(particle.PBestProfit + "\t" + particle.PBestRisk);
            //}

            //File.WriteAllText(Application.StartupPath + "\\PsoResult.txt",
            //                  sbProfit.ToString() + sbRisk.ToString() + sbPBest.ToString());
            MessageBox.Show("ok");
        }

        private double SigMoid(double v)
        {
            return 1 / (1 + Math.Exp(-v));
        }

        private void ComputeFitness(Particle particle)
        {
            //暂时取之差

            Example example = new Example();
            example.Z = particle.Position;
            //lingo计算收益
            LingoHelper.RunProfit(example);
            double profit = example.Optimum;
            particle.Profit = profit;

            //lingo计算风险
            LingoHelper.RunRisk(example);
            double risk = example.Optimum;
            particle.Risk = risk;

            //取差
            particle.Fitness = profit / risk;
            // Trace.WriteLine(string.Format("Fitness={0}-{1}={2}", profit, risk, particle.Fitness));
        }

        private Particle GetRandomInitialParticle()
        {
            Particle particle = new Particle();
            for (int j = 0; j < 3; j++)
            {
                for (int k = 0; k < 10; k++)
                {
                    particle.Position = new double[3, 10];
                    particle.Velocity = new double[3, 10];
                    particle.Velocity[j, k] = 0;
                }
            }

            //确定第一个计划期的
            for (int j = 0; j < 10; j++)
            {
                particle.Position[0, j] = 1;
            }

            //确定第二个计划期的
            int z = random.Next(2);
            particle.Position[1, 0] = particle.Position[1, 1] = particle.Position[1, 2] = z;

            z = random.Next(2);
            particle.Position[1, 3] = particle.Position[1, 4] = z;

            z = random.Next(2);
            particle.Position[1, 5] = particle.Position[1, 6] = z;

            z = random.Next(2);
            particle.Position[1, 7] = particle.Position[1, 8] = particle.Position[1, 9] = z;

            //确定第三个计划期的
            for (int j = 0; j < 10; j++)
            {
                particle.Position[2, j] = random.Next(2);
            }

            return particle;
        }


        private List<Particle> GetInitialParticles()
        {
            //在这里，每个pbset设置为自己的position
            List<Particle> particles = new List<Particle>();

            for (int i = 0; i < familySize; i++)
            {

                Particle particle = new Particle();
                particle.PBestRisk = double.PositiveInfinity;
                particles.Add(particle);
                for (int j = 0; j < 3; j++)
                {
                    for (int k = 0; k < 10; k++)
                    {
                        particle.Position = new double[3, 10];
                        particle.Velocity = new double[3, 10];
                        particle.Velocity[j, k] = 0;
                    }
                }

                //确定第一个计划期的
                for (int j = 0; j < 10; j++)
                {
                    particle.Position[0, j] = 1;
                }

                //确定第二个计划期的
                int z = random.Next(2);
                particle.Position[1, 0] = particle.Position[1, 1] = particle.Position[1, 2] = z;

                z = random.Next(2);
                particle.Position[1, 3] = particle.Position[1, 4] = z;

                z = random.Next(2);
                particle.Position[1, 5] = particle.Position[1, 6] = z;

                z = random.Next(2);
                particle.Position[1, 7] = particle.Position[1, 8] = particle.Position[1, 9] = z;

                //确定第三个计划期的
                for (int j = 0; j < 10; j++)
                {
                    particle.Position[2, j] = random.Next(2);
                }
            }

            return particles;
        }

        private void CapacityBundle(Particle particle)
        {
            //检查z
            //peroid 2 only
            if ((particle.Position[1, 0] == particle.Position[1, 1]) && (particle.Position[1, 0] == particle.Position[1, 2]))
            {
            }
            else
            {
                int z = random.Next(2);
                particle.Position[1, 0] = particle.Position[1, 1] = particle.Position[1, 2] = z;

            }

            if (particle.Position[1, 3] != particle.Position[1, 4])
            {
                int z = random.Next(2);
                particle.Position[1, 3] = particle.Position[1, 4] = z;
            }

            if (particle.Position[1, 5] != particle.Position[1, 6])
            {
                int z = random.Next(2);
                particle.Position[1, 5] = particle.Position[1, 6] = z;
            }
            if ((particle.Position[1, 7] == particle.Position[1, 8]) && (particle.Position[1, 7] == particle.Position[1, 9]))
            {
            }
            else
            {
                int z = random.Next(2);
                particle.Position[1, 7] = particle.Position[1, 8] = particle.Position[1, 9] = z;
            }

        }

        private void WorkCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            btnStart.Enabled = true;
            tbxIterationTimes.Enabled = true;
            tbxParticleSize.Enabled = true;

            MessageBox.Show("Job is done!!");
        }

        private void ShowProgress(object sender, ProgressChangedEventArgs e)
        {
            lblPercentage.Text = e.ProgressPercentage.ToString() + " %";

            lblCurrent.Text = string.Format("{0}/{1}", e.UserState, iterationTimes);

            progressBar1.Value = e.ProgressPercentage;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            DataGenerator generator = new DataGenerator();
            generator.CreateData();
        }


        private List<Particle> GetALl()
        {
            List<Particle> particles = new List<Particle>();

            double total = Math.Pow(2, 14);
            string bcdText;
            for (int i = 1; i < total; i++)
            {
                bcdText = BCD.GetByBinary(i);
                int[] bcd = new int[14];
                for (int j = 0; j < 14; j++)
                {
                    bcd[j] = Convert.ToInt32(bcdText[18 + j].ToString());
                }

                Particle particle = new Particle();
                particle.Position = new double[3, 10];
                particles.Add(particle);

                //确定第一个计划期的
                for (int j = 0; j < 10; j++)
                {
                    particle.Position[0, j] = 1;
                }

                //确定第二个计划期的
                particle.Position[1, 0] = particle.Position[1, 1] = particle.Position[1, 2] = bcd[0];

                particle.Position[1, 3] = particle.Position[1, 4] = bcd[1];

                particle.Position[1, 5] = particle.Position[1, 6] = bcd[2];

                particle.Position[1, 7] = particle.Position[1, 8] = particle.Position[1, 9] = bcd[3];

                //确定第三个计划期的
                for (int j = 0; j < 10; j++)
                {
                    particle.Position[2, j] = bcd[4 + j];
                }
            }
            return particles;
        }
        private void button2_Click(object sender, EventArgs e)
        {
            BackgroundWorker worker = new BackgroundWorker();

            worker.DoWork += DoWorkEnmum;
            //worker.ProgressChanged += ShowProgress;
            worker.RunWorkerCompleted += WorkCompleted;
            //worker.WorkerReportsProgress = true;
            //worker.WorkerSupportsCancellation = true;

            worker.RunWorkerAsync();

        }

        private void DoWorkEnmum(object sender, DoWorkEventArgs e)
        {
            Trace.WriteLine("Getting All Samples");

            List<Particle> particles = GetALl();
            int i = 1;
            foreach (Particle particle in particles)
            {

                ComputeFitness(particle);
                DataGateWay.InsertEnumAll(GetString(particle.Position), particle.Profit, particle.Risk);
                Trace.WriteLine(string.Format("{0}  {1}  {2}", i, particle.Profit, particle.Risk));
            }
        }
        private string GetString(double[,] inp)
        {
            string outp = "";
            for (int i = 0; i < inp.GetLength(0); i++)
            {
                for (int j = 0; j < inp.GetLength(1); j++)
                {
                    outp += inp[i, j];

                }
            }
            return outp;
        }


    }
}
